<script setup>
// 导入Vue核心API：依赖注入、响应式、 props/emit 定义
import { provide, reactive, defineProps, defineEmits } from 'vue';

/**
 * 表单组件Props定义
 * @property {Object} model - 表单数据对象（双向绑定）
 * @property {Object} rules - 表单验证规则
 */
const props = defineProps({
  model: {
    type: Object,
    required: true,
    description: '表单数据对象，用于双向绑定表单值'
  },
  rules: {
    type: Object,
    default: () => ({}),
    description: '表单验证规则，键为字段名，值为验证规则数组'
  }
});

/**
 * 表单事件定义
 * @event submit - 表单验证通过后触发，返回表单数据
 * @event validate-status - 验证状态变化时触发，返回验证结果和错误信息
 */
const emit = defineEmits(['submit', 'validate-status']); // 修正事件名避免冲突

// 错误信息容器：存储各字段验证错误信息 { field: errorMessage }
const errors = reactive({});

/**
 * 表单状态管理对象
 * 包含表单数据、验证规则、字段注册和验证逻辑
 */
const formState = reactive({
  model: props.model, // 表单数据（引用外部传入的model）
  rules: props.rules, // 验证规则（引用外部传入的rules）
  fields: [], // 已注册的表单字段集合
  errors, // 错误信息对象（响应式）

  /**
   * 注册表单字段
   * 由BaseFormItem子组件调用，收集所有需要验证的字段
   * @param {Object} field - 字段信息 { key: 字段名, getValue: 获取值的函数 }
   */
  registerField(field) {
    this.fields.push(field);
  },

  /**
   * 执行表单验证
   * @returns {Promise<Object>} 验证结果 { isValid: 布尔值, errors: 错误信息对象 }
   */
  validate: async () => {
    // 1. 初始化错误信息对象
    const errors = {};
    const fields = formState.fields;

    // 2. 遍历所有已注册字段进行验证
    for (const field of fields) {
      const { key, getValue } = field;
      const value = getValue(); // 获取字段当前值
      const fieldRules = props.rules[key] || []; // 获取该字段的验证规则

      // 3. 遍历该字段的所有验证规则
      for (const rule of fieldRules) {
        // 3.1 支持自定义验证函数（最高优先级）
        if (rule.validator && typeof rule.validator === 'function') {
          try {
            // 自定义验证函数是回调风格，转换为Promise以便await
            await new Promise((resolve, reject) => {
              rule.validator(rule, value, (err) => {
                if (err)
                  reject(err); // 验证失败：传递错误信息
                else resolve(); // 验证成功
              });
            });
          } catch (err) {
            errors[key] = err.message; // 记录错误信息
            break; // 跳出当前字段的规则循环
          }
        } else {
          // 3.2 内置验证规则
          const { required, message, pattern, min, max } = rule;

          // 3.2.1 必填验证
          if (required && !value) {
            errors[key] = message || '此字段为必填项';
            break; // 验证失败，跳出规则循环
          }

          // 3.2.2 正则表达式验证（值存在时才验证）
          if (pattern && value && !pattern.test(value)) {
            errors[key] = message || '格式验证失败';
            break;
          }

          // 3.2.3 长度验证（值存在时才验证）
          if ((min || max) && value) {
            if (min && value.length < min) {
              errors[key] = message || `至少${min}个字符`;
              break;
            }
            if (max && value.length > max) {
              errors[key] = message || `最多${max}个字符`;
              break;
            }
          }
        }
      }
    }

    // 4. 更新响应式错误信息并触发验证状态事件
    formState.errors = errors;
    const isValid = Object.keys(errors).length === 0;
    emit('validate-status', isValid, errors);

    // 5. 返回验证结果
    return { isValid, errors };
  }
});

// 提供表单状态给子组件（BaseFormItem）
provide('form', formState);

/**
 * 表单提交处理函数
 * 触发验证，验证通过后提交表单
 */
function onSubmit() {
  1;
  // 调用验证方法，验证通过后触发submit事件
  formState.validate().then((result) => {
    if (result.isValid) {
      emit('submit', formState.model); // 提交表单数据
    }
  });
}
</script>

<template>
  <!-- 表单容器，阻止默认提交行为，绑定自定义提交处理 -->
  <form @submit.prevent="onSubmit">
    <!-- 插槽：用于插入BaseFormItem等表单元素 -->
    <slot></slot>
  </form>
</template>
